﻿using MyBookReadsList.Models;
using MyBookReadsList.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace MyBookReadsList.Data
{
    class DataPersister
    {
        protected static string AccessToken { get; set; }

        private const string BaseServicesUrl = "http://bookreaderservice.apphb.com/api/";

        // start Stuff for validation
        private const int MinUsernameLength = 6;
        private const int MaxUsernameLength = 30;
        private const string ValidUsernameCharacters =
            "qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM1234567890_.";

        private const string SessionKeyChars =
            "qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM";

        private const int SessionKeyLength = 50;

        private const int Sha1Length = 40;

        // end stuff for validation
        public static void AddShelf(Shelf newShelf)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

            HttpRequester.Post<Shelf>(BaseServicesUrl + "shelves", newShelf, headers);

        }

        internal static void RegisterUser(string username, string email, string authenticationCode)
        {
            //Validation!!!!!
            //validate username
            //validate authentication code
            //use validation from WebAPI

            ValidateUsername(username);
            ValidateAuthCode(authenticationCode);
            
            var userModel = new User()
            {
                username = username,
                authCode = authenticationCode
            };
            HttpRequester.Post(BaseServicesUrl + "user/register",
                userModel);
        }

        internal static string LoginUser(string username, string authenticationCode)
        {
            //Validation!!!!!
            //validate username
            //validate authentication code
            //use validation from WebAPI

            ValidateUsername(username);
            ValidateAuthCode(authenticationCode);

            var userModel = new User()
            {
                username = username,
                authCode = authenticationCode
            };

            string loginResponse = HttpRequester.Post<string>(BaseServicesUrl + "user/login",
                userModel);
            AccessToken = loginResponse;
            return loginResponse;
        }

        internal static bool LogoutUser()
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;
            var isLogoutSuccessful = HttpRequester.Put(BaseServicesUrl + "user/logout",null, headers);
            return isLogoutSuccessful;
        }

        internal static IEnumerable<BookListViewModel> GetBooksList(CategorysViewModel category)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

            var todoListsModels =
                HttpRequester.Get<IEnumerable<BookListViewModel>>(BaseServicesUrl + "books/getallbooks", headers);
            if (category == null)
            {
                return todoListsModels.AsQueryable().Select(model =>
                new BookListViewModel()
                {
                    Id = model.Id,
                    Title = model.Title,
                    CategoryDetails = model.CategoryDetails,
                    AuthorInfo = model.AuthorInfo
                });
            }
            else
            {
                return todoListsModels.Where(m => m.CategoryDetails == category.Title).
                     Select(model =>
                new BookListViewModel()
                     {
                         Id = model.Id,
                         Title = model.Title,
                         CategoryDetails = model.CategoryDetails,
                         AuthorInfo = model.AuthorInfo
                     });
            }
        }

        internal static IEnumerable<CategorysViewModel> GetCategorys()
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

            var todoListsModels =
                HttpRequester.Get<IEnumerable<CategorysViewModel>>(BaseServicesUrl + "categories/getallcategories", headers);
            
            return todoListsModels.AsQueryable().Select(model =>
            new CategorysViewModel()
            {
                Title = model.Title,
            });
        }

        internal static IEnumerable<Shelf> GetShelves()
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

          var shelves =
                HttpRequester.Get<IEnumerable<Shelf>>(BaseServicesUrl + "shelves/getusershelves", headers);

            return shelves;
        }

        internal static void RemoveShelf(Shelf shelf)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

            HttpRequester.Delete(BaseServicesUrl + "shelves/" + shelf.Id + "/remove", headers);
        }

        internal static void SaveShelves(IEnumerable<Shelf> shelves)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

            foreach (var shelf in shelves)
            {
                var a =HttpRequester.Put(BaseServicesUrl + "shelves/" + shelf.Id + "/update", shelf, headers);
            }
        }

        internal static IEnumerable<SimpleBook> GetBooks(Shelf shelf)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

            var books =
               HttpRequester.Get<IEnumerable<SimpleBook>>(BaseServicesUrl + "shelves/" + shelf.Id + "/books", headers);

            return books;
        }

        internal static void RemoveBook(Shelf shelf, SimpleBook simpleBook)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

            HttpRequester.Put(BaseServicesUrl + "shelves/" + shelf.Id + "/removeBook", simpleBook.Id, headers);
        }

        internal static BookViewModel GetBookByTitle(string title)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;
            //api/books/getallbooks
            var books =
               HttpRequester.Get<IEnumerable<Book>>(BaseServicesUrl + "books/getallbooks", headers);

            var book = (books.Where(x=>x.Title == title)).FirstOrDefault();
            BookViewModel b = new BookViewModel() 
            { 
                Book = book,
            };
            return b;          
        }

        internal static IEnumerable<Comment> LoadComments(string bookID)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

           var allComments =
               HttpRequester.Get<IEnumerable<Comment>>(BaseServicesUrl + "Comments?bookid=" + bookID, headers);

           return allComments;
        }

        internal static void AddComment(CommentAdd currentComment)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;

            HttpRequester.Post<Shelf>(BaseServicesUrl + "comments/postcomments", currentComment, headers);
        }

        private static void ValidateUsername(string username)
        {
            if (username == null)
            {
                throw new ArgumentNullException("Username cannot be null");
            }
            else if (username.Length < MinUsernameLength)
            {
                throw new ArgumentOutOfRangeException(
                    string.Format("Username must be at least {0} characters long",
                    MinUsernameLength));
            }
            else if (username.Length > MaxUsernameLength)
            {
                throw new ArgumentOutOfRangeException(
                    string.Format("Username must be less than {0} characters long",
                    MaxUsernameLength));
            }
            else if (username.Any(ch => !ValidUsernameCharacters.Contains(ch)))
            {
                throw new ArgumentOutOfRangeException(
                    "Username must contain only Latin letters, digits .,_");
            }
        }

        private static void ValidateAuthCode(string authCode)
        {
            if (authCode == null || authCode.Length != Sha1Length)
            {
                throw new ArgumentOutOfRangeException("Password should be encrypted");
            }
        }

        internal static void AddBookToShelf(BookViewModel bookViewModel, Shelf shelf)
        {
            var headers = new Dictionary<string, string>();
            headers["X-sessionKey"] = AccessToken;
            BookToShelf bookToShelf = new BookToShelf();
            bookToShelf.bookId = bookViewModel.Book.Id;
            bookToShelf.shelfId = shelf.Id.ToString();

            HttpRequester.Post<Shelf>(BaseServicesUrl + "books/addbooktoshelf", bookToShelf, headers);
        }
    }
}